package com.ruoyi.seckill;

import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.system.domain.SeckillGoods;
import com.ruoyi.system.domain.SeckillOrder;
import com.ruoyi.system.mapper.SeckillGoodsMapper;
import com.ruoyi.system.mapper.SeckillOrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@Slf4j
public class SeckillMQConsumer {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    @Autowired
    private SeckillOrderMapper seckillOrderMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisCache redisCache;

    @RabbitListener(queues = "seckill.queue")
    public void handleSeckillMessage(SeckillMessage message) throws Exception{
        Long userId = message.getUserId();
        Long goodsId = message.getGoodsId();

        // 幂等性校验：判断用户是否已抢购成功
        String userSetKey = Constants.SECKILL_GOOD + goodsId + Constants.SECKILL_GOOD_SUCCESS_USERS;
        Boolean isAlreadySeckilled = stringRedisTemplate.opsForSet().isMember(userSetKey, userId.toString());
        if (Boolean.TRUE.equals(isAlreadySeckilled)) {
            // 已经抢购过，直接返回
            return;
        }

        try {
            doHandleSeckill(userId, goodsId, userSetKey);
        } catch (Exception e) {
            // 记录日志或发送告警
            log.error("秒杀处理异常，userId={}, goodsId={}", userId, goodsId, e);
            // 可根据业务需求决定是否重新入队
            throw new Exception("处理失败，重新入队", e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void doHandleSeckill(Long userId, Long goodsId, String userSetKey) {
        // 1. 使用数据库乐观锁扣减库存
        SeckillGoods goods = seckillGoodsMapper.selectById(goodsId);
        if (goods == null) {
            // 商品不存在，记录日志并返回
            log.warn("商品不存在，goodsId={}", goodsId);
            return;
        }

        int updateCount = seckillGoodsMapper.decreaseStockWithVersion(goodsId, goods.getVersion());

        if (updateCount <= 0) {
            // 乐观锁更新失败，代表库存不足或版本号不对（数据已被其他线程修改）
            rollbackRedisStock(userId, goodsId);
            return;
        }

        // 2. 库存扣减成功，创建订单
        SeckillOrder order = new SeckillOrder();
        order.setUserId(userId);
        order.setGoodsId(goodsId);
        order.setStatus(0); // 未支付
        seckillOrderMapper.insert(order);

        // 成功后才写入 Redis 用户记录，用于防重
        stringRedisTemplate.opsForSet().add(userSetKey, userId.toString());
    }


    /**
     * 回滚Redis中的库存和用户记录
     */
    private void rollbackRedisStock(Long userId, Long goodsId) {
        String stockKey = "seckill:goods:" + goodsId + ":stock";
        String userSetKey = "seckill:goods:" + goodsId + ":success_users";
        // 库存回滚1
        stringRedisTemplate.opsForValue().increment(stockKey);
        // 从成功用户集合中移除当前用户
        stringRedisTemplate.opsForSet().remove(userSetKey, userId.toString());
    }
}
